package com.jsurf;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/**
 * Created by: Eduardo Quintana Contreras
 * Date: 6/06/11
 * Time: 03:39 PM
 */
public class ScaleConsistencyCheck {
	private static ArrayList<Scale> scales = new ArrayList<Scale>();
	private static float scaleThreshold = 0.5f;

	public static ArrayList<Map<InterestPoint, InterestPoint>> compute(Map<InterestPoint, InterestPoint> matches) {
		ArrayList<Map<InterestPoint, InterestPoint>> ret = new ArrayList<Map<InterestPoint, InterestPoint>>();
		if (matches.size() > 2) {
			// get the ratio of scales
			scales.clear();
			for (Entry<InterestPoint, InterestPoint> entry : matches.entrySet()) {
				scales.add(new Scale(entry.getKey(), entry.getValue(), entry.getKey().getScale() / entry.getValue().getScale()));
			}

			//Sort the scale ratios
			Collections.sort(scales);

			// get the median
			float median;
			if (scales.size() % 2 == 1) {
				median = scales.get((scales.size() + 1) / 2 - 1).scale;
			}
			else {
				float lower = scales.get(scales.size() / 2 - 1).scale;
				float upper = scales.get(scales.size() / 2).scale;
				median = (lower + upper) / 2f;
			}

//			System.out.println("median = " + median);

			// get the matches which its scale is inside the threshold
			Map<InterestPoint, InterestPoint> matchesPruned = new HashMap<InterestPoint, InterestPoint>(),
					matchesExcluded = new HashMap<InterestPoint, InterestPoint>();
			int consensusSet = 0;
			for (Scale scale : scales) {
				if (Math.abs(scale.scale - median) <= scaleThreshold) {
					consensusSet++;
					matchesPruned.put(scale.ipQ, scale.ipD);
//					scale.inConsensusSet = true;
				}
				else {
					matchesExcluded.put(scale.ipQ, scale.ipD);
				}
			}

//			System.out.println("Consensus Set = " + consensusSet + " out of " + matches.size());

			ret.add(matchesPruned);
			ret.add(matchesExcluded);

			return ret;
//			return scales;
		}
		else {
			ret.add(matches);
			ret.add(null);

			return ret;
//			return new ArrayList<Scale>();
		}
	}
}

class Scale implements Comparable<Scale> {
	public float scale;
	public InterestPoint ipQ, ipD;
	public boolean inConsensusSet = false;

	public Scale(InterestPoint ipQ, InterestPoint ipD, float scale) {
		this.ipQ = ipQ;
		this.ipD = ipD;
		this.scale = scale;
	}

	public int compareTo(Scale s) {
		return Float.compare(s.scale, this.scale);
	}
}
